﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Solidi
{
	public class ReferenceTracker
	{
		private IDependencyLifestyle _lifestyle;
		private Dictionary<object, Reference> _tokens = new Dictionary<object, Reference>();

		public ReferenceTracker(IDependencyLifestyle lifestyle)
		{
			_lifestyle = lifestyle;
		}

		public Reference Resolve(Func<object> factory)
		{
			object token = _lifestyle.ResolveToken();

			Reference reference;

			lock (_tokens)
			{
				if (_tokens.TryGetValue(token, out reference))
				{
					reference.Increment();
				}
				else
				{
					reference = new Reference(factory(), token);

					_tokens.Add(token, reference);
				}
			}

			return reference;
		}

		public DependencyDisposal Release(Reference reference)
		{
			lock (_tokens)
			{
				if (reference.Unreferenced)
				{
					return DependencyDisposal.ReferenceCountMismatch;
				}

				reference.Decrement();

				if (reference.Unreferenced)
				{
					if (_lifestyle.ReleaseToken(reference.Token))
					{
						_tokens.Remove(reference.Token);

						return DependencyDisposal.Dispose;
					}
				}
			}

			return DependencyDisposal.ReferenceCountDecremented;
		}
	}
}
